<?php

class Account_model extends Model
{
	const RECOVERY_KEY_EXPIRATION = 2; # hours
	const REMEMBERME_TOKEN_EXPIRE = 7; # days
	const EMAIL_CONFIRM_KEY_EXPIRE = 2; # hours
	
	function Account_model()
	{
		parent::Model();
	}
	
	
	public function get($user_id)
	{
		$user_id = (int)$user_id;	
		$sql = "SELECT user_id, email, password, salt, timezone, name, date_created, last_login
				FROM user 
				WHERE user_id = $user_id";
		$result = $this->db->query($sql);
		return $result->row();	
	}
	
	
	public function create($user)
	{
		$email 	  = $this->db->escape($user['email']);
		$salt 	  = $this->db->escape($user['salt']);
		$password = $this->db->escape($user['password']);
		//$name 	  = $this->db->escape($user['name']);
		$ip 	  = $this->db->escape($user['ip']);
		
		$date_created = local_to_gmt(time());
		$last_login = local_to_gmt(time());
		
		$sql = "INSERT INTO user (email, password, salt, name, date_created, timezone, last_login, last_login_ip)
				VALUES ($email, $password, $salt, '', $date_created, 'UP2', $last_login, $ip)";
					
		$this->db->query($sql);
		
		if($this->db->affected_rows() == 0) return FALSE;
		
		return $this->db->insert_id();
	}
	
	
	
	public function isUniqueEmail($email)
	{
		$email = $this->db->escape($email);
		$sql = "SELECT user_id FROM user WHERE email = $email";
		$result = $this->db->query($sql);

		if($result->num_rows() > 0) return FALSE;
		return TRUE;
	}
	
	
	public function login($email)
	{
		$email = $this->db->escape($email);
		
		$sql = "SELECT user_id, email, password, salt, name, timezone FROM user WHERE email = $email AND is_active = 1";
		$query = $this->db->query($sql);
		
		# user not found
		if($query->num_rows() == 0) return FALSE;
		
		$res = $query->result();
		return $res[0];
	}
	
	
	public function updateLastLogin($user_id, $ip)
	{
		$ip = $this->db->escape($ip);
		$last_login = local_to_gmt(time());
		
		$sql = "UPDATE user SET last_login = $last_login, last_login_ip = $ip, login_counter = login_counter + 1 WHERE user_id = " . (int)$user_id;
		$this->db->query($sql);
	}
	
	
	# http://jaspan.com/improved_persistent_login_cookie_best_practice
	public function rememberUser($user_id, $email)
	{
		# clean old remembered users
		$sql = "DELETE FROM user_remember WHERE expire < NOW()";
		$this->db->query($sql);
		
		$email = $this->db->escape($email);
		$user_id = (int)$user_id;
		
		$token = new stdClass();
		$token->value = substr( md5(uniqid(rand(),true) . $email), 0, 16);
		# this second token is used to distinguish replay use of token
		# it does not change when updating the value of the token
		# it changes (in fact it's when it is created) only when a new record with token is inserted
		$token->series = substr( md5(uniqid(rand(),false) . $email), 0, 16);
		$token->expire = time() + self::REMEMBERME_TOKEN_EXPIRE * 60 * 60 * 24; # REMEMBERME_TOKEN_EXPIRE days 
		
		$t = $this->db->escape($token->value);
		$s = $this->db->escape($token->series);
		
		$sql = "INSERT INTO user_remember
				SET user_id = $user_id,
					email = $email,
					token = $t,
					series_identifier = $s,
					expire = FROM_UNIXTIME($token->expire)";
							
		$this->db->query($sql);
		if($this->db->affected_rows() == 0) return FALSE;
		
		return $token;
	}
	
	
	public function unrememberUser($email, $token)
	{
		$email = $this->db->escape($email);
		$token = $this->db->escape($token);
		
		$sql = "DELETE FROM user_remember WHERE email = $email AND token = $token";
		log_message('debug', $sql);
		$this->db->query($sql);
	}
	
	
	public function unrememberUserEverywhere($email)
	{
		$email = $this->db->escape($email);		
		$sql = "DELETE FROM user_remember WHERE email = $email";
		log_message('debug', $sql);
		$this->db->query($sql);
	}
	
	
	public function createRecoveryKey($email)
	{
		$email = $this->db->escape($email);
		$key = md5( $email . uniqid(rand(), true));
		
		# delete old recovery keys (expired) or duplicate email
		$sql = "DELETE FROM user_recover WHERE expire < NOW() OR email = $email";
		$this->db->query($sql);
		
		$sql = "INSERT INTO user_recover 
				SET email = $email, 
					recovery_key = '$key', 
					expire = NOW() + INTERVAL " . self::RECOVERY_KEY_EXPIRATION . " HOUR";
						
		$this->db->query($sql);
		
		if($this->db->affected_rows() == 0) return FALSE;
		return $key;
	}
	
	
	public function checkRecoveryKey($key)
	{
		# clean old (expired) recovery records
		$this->db->query('DELETE FROM user_recover WHERE expire < NOW()');
		
		$key = $this->db->escape($key);
		$sql = "SELECT email FROM user_recover WHERE recovery_key = $key AND expire > NOW()";
		$result = $this->db->query($sql);
		
		if($result->num_rows() == 0) return FALSE;
		
		$row = $result->row();
		return $row->email;
	}
	
	
	public function invalidateUserRecover($email)
	{
		$email = $this->db->escape($email);
		$sql = "DELETE FROM user_recover WHERE email = $email";
		$this->db->query($sql);
	}
	
	
	public function changePass($user)
	{
		$email 	 = $this->db->escape($user['email']);
		$newpass = $this->db->escape($user['newpass']);
		$salt 	 = $this->db->escape($user['salt']);
		
		$sql = "DELETE FROM user_recover WHERE email = $email";
		$this->db->query($sql);

		$sql = "UPDATE user SET password = $newpass, salt = $salt WHERE email = $email";
		$result = $this->db->query($sql);		
		
		if($this->db->affected_rows() == 0) return FALSE;
		return TRUE;
	}
	
	
	public function saveProfile($user_id, $user)
	{
		$result = new stdClass();
		$result->status = 0; # OK
		
		# update profile information
		$name  = $this->db->escape($user['name']);
		$tz	   = $this->db->escape($user['tz']);
		$sql = "UPDATE user SET name = $name, timezone = $tz WHERE user_id = $user_id";
		$this->db->query($sql);
		
		# check if email is new and add it to the confirm email table
		if($user['newemail'] !== $user['email'])
		{
			$sql = "DELETE FROM user_confirm_email WHERE user_id = $user_id";
			$this->db->query($sql);
			
			$new_email = $this->db->escape($user['newemail']);
			$confirm_key = md5( $new_email . uniqid(rand(), true));
			$key = $this->db->escape($confirm_key);
			$email = $this->db->escape($user['email']);
			
			$sql = "INSERT IGNORE INTO user_confirm_email
					SET user_id = $user_id,
						email = $email,
						new_email = $new_email,
						confirm_key = $key,
						expire = NOW() + INTERVAL " . self::EMAIL_CONFIRM_KEY_EXPIRE . " HOUR";
			
			log_message('debug', $sql);
			$this->db->query($sql);
			
			if($this->db->affected_rows() == 0) 
				$result->status = -1;
			else
				$result->key = $confirm_key;
		}
		
		return $result;
	}
	
	
	public function checkConfirmEmailKey($key)
	{
		$key = $this->db->escape($key);
		$sql = "SELECT user_id FROM user_confirm_email WHERE confirm_key = $key AND expire > NOW()";
		log_message('debug', $sql);
		$query = $this->db->query($sql);
		
		if($query->num_rows() == 0) return FALSE;
		
		return TRUE;
	}
	
	
	public function changeEmail($key)
	{
		$key = $this->db->escape($key);
		$sql = "SELECT user_id, email, new_email FROM user_confirm_email WHERE confirm_key = $key AND expire > NOW()";
		log_message('debug', $sql);
		$query = $this->db->query($sql);
				
		if($query->num_rows() == 0) return FALSE;
		
		$result = $query->row();
				
		$email = $this->db->escape($result->email);
		$new_email = $this->db->escape($result->new_email);
		$user_id = (int)$result->user_id;
		
		$sql = "UPDATE user SET email = $new_email WHERE user_id = $user_id";
		log_message('debug', $sql);
		$this->db->query($sql);
		if($this->db->affected_rows() == 0) return FALSE;
		
		$sql = "DELETE FROM user_confirm_email WHERE user_id = $user_id";
		log_message('debug', $sql);
		$this->db->query($sql);
				
		$sql = "DELETE FROM user_remember WHERE user_id = $user_id";
		log_message('debug', $sql);
		$this->db->query($sql);
		
		$sql = "DELETE FROM user_recover WHERE email = $email";
		log_message('debug', $sql);
		$this->db->query($sql);
		
		return $result->new_email;
	}
	
	
	public function remove($user_id, $email)
	{
		$email = $this->db->escape($email);
		
		$sql = "DELETE FROM user WHERE user_id = $user_id";
		$this->db->query($sql);
		
		$sql = "DELETE FROM user_remember WHERE user_id = $user_id";
		$this->db->query($sql);
		
		$sql = "DELETE FROM user_confirm_email WHERE user_id = $user_id";
		$this->db->query($sql);
		
		$sql = "DELETE FROM user_recover WHERE email = $email";
		$this->db->query($sql);
		
		return true;
	}
}